#pragma once

#include "Log.hpp"
#include <string>
#include <mysql/mysql.h>

namespace Util
{
    const unsigned int default_mysql_port = 3306;
    const std::string default_mysql_db = "boardgame";
    const std::string default_mysql_host = "127.0.0.1";

    class mysql 
    {
    public:

        /**
         * @brief MySQL 构造函数。
         *
         * @param user 数据库用户的用户名。
         * @param passwd 数据库用户的密码。
         * @param db 要连接的数据库名称。
         * @param host 数据库主机地址。
         * @param port 数据库连接端口号，默认为默认 MySQL 端口号。
         *
         * @details 此构造函数用于创建 MySQL 对象，并根据传入的参数初始化数据库连接。
         *          在初始化之后，将尝试初始化 MySQL 库，并创建数据库连接。
         *          若初始化过程中出现错误，将通过日志系统记录 FATAL 级别的错误消息，并返回。
         *          若成功初始化数据库连接，将在日志系统中记录 NORMAL 级别的成功消息。
         */
        mysql(
            const std::string& user, 
            const std::string& passwd, 
            const std::string& db = default_mysql_db, 
            const std::string& host = default_mysql_host, 
            unsigned int port=default_mysql_port
        ) noexcept
            : _port(port), _sql(nullptr), _host(host), _user(user), _passwd(passwd), _db(db)
        {
            MYSQL* sql = mysql_init(nullptr);
            if (sql == nullptr)
            {
                LOG(FATAL, "mysql init error");
                return;
            }
            _sql = sql;
            LOG(NORMAL, "mysql init success");
        }
        
        ~mysql() noexcept
        {
            if (_sql != nullptr)
            {
                mysql_close(_sql);
                _sql = nullptr;
            }
        }

        /**
         * @brief 初始化 MySQL 数据库连接。
         * @details
         * 此函数初始化 MySQL 库并建立数据库连接。
         * 它将字符集设置为 UTF-8，以支持 Unicode 数据。
         * 如果在初始化或连接过程中出现任何错误，
         * 将记录适当的错误消息，并在不建立连接的情况下返回。
         */
        void init();

        /**
         * @brief 执行 MySQL 查询。
         * @param command 要执行的 SQL 查询语句。
         * @return 如果查询成功执行，则返回 true；否则返回 false。
         */
        bool query(const std::string& command)
        {
            int ret = mysql_query(_sql, command.c_str());
            if (ret != 0)
            {
                LOG(WARNING, "mysql query error: %s", mysql_error(_sql));
                return false;
            }
            LOG(NORMAL, "mysql query success");
            return true;
        }

        MYSQL* getSQL()
        {
            return _sql;
        }
    private:
        unsigned int _port;
        MYSQL* _sql;
        std::string _host;
        std::string _user;
        std::string _passwd;
        std::string _db;
    };

    void mysql::init()
    {
        if (mysql_real_connect(_sql, _host.c_str(), _user.c_str(), _passwd.c_str(), _db.c_str(), _port, nullptr, 0) == nullptr)
        {
            LOG(FATAL, "mysql connect error: %s", mysql_error(_sql));
            mysql_close(_sql);
            return;
        }
        LOG(NORMAL, "mysql connect success");

        if (mysql_set_character_set(_sql, "utf8") != 0)
        {
            LOG(FATAL, "mysql character_set error: %s", mysql_error(_sql));
            mysql_close(_sql);
            return;
        }
        LOG(NORMAL, "mysql character_set success");
    }
}